package cn.shadow.server.hanlder;

import cn.shadow.message.Worker;
import cn.shadow.message.WorkerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SingleDecodeHandler extends LengthFieldBasedFrameDecoder {
    private static final int DEFAULT_MSG_SIZE_LIMIT = 1200;
    private ChannelGroup group;
    private WorkerFactory factory;
    private Worker worker;
    private Channel channel;
    public static AttributeKey<Worker> WORKER_KEY = AttributeKey.valueOf("worker_key");

    /**
     * 第1个参数：maxFrameLength 表示包的最大长度
     * 第2个参数: lengthFieldOffset 长度域的偏移量，也就是ByteBuf从什么位置开始就是length字段了
     * 第3个参数: lengthFieldLength 长度域
     * 第4个参数：lengthAdjustment 有些情况可能会把header也包含到length长度中，
     * 或者length字段后面还有一些不包括在length长度内的，可以通过lengthAdjustment调节
     * 由于整个消息（包含消息头）的长度往往大于消息体的长度，所以，lengthAdjustment为负数。
     * 第5个参数：initialBytesToStrip  表示netty拿到一个完整的数据包之后向业务解码器传递之前，应该跳过多少字节
     * 比如这个参数是4，而长度域的值也是4，就是得到一个不带长度域的数据包
     */
    public SingleDecodeHandler(WorkerFactory factory, ChannelGroup group) {
//        super(DEFAULT_MSG_SIZE_LIMIT, 0, 2, 0, 2);
        super(DEFAULT_MSG_SIZE_LIMIT, 0, 4, 0, 4);
        this.group = group;
        this.factory = factory;
    }

    @Override
    protected ByteBuf extractFrame(ChannelHandlerContext ctx, ByteBuf buffer, int index, int length) {
        try {
            ByteBuf input = buffer.slice(index, length);  //消息的入口
            worker.onMessage(input);
        } catch (NullPointerException ex) {
            if (worker == null) {
                // 正常的. disconnect后, 有些之前收到的消息
                return null;
            } else {
                log.error("extractFrame出错", ex);
            }
        } catch (Throwable ex) {
            log.error("extractFrame出错", ex);
        }
        return null;
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) {
        channel = ctx.channel();
    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        log.info("连接服务器成功");
        worker = factory.newWorker(channel); //在登录的时候创建了一个消息工人，用于消息的传输
        group.add(channel); //将这个通道加到通道组中
        //通道的附件为工人，这样讲通道和消息工人绑定起来了
        channel.attr(WORKER_KEY).set(worker);
        log.info("通道已建立");
        worker.onConnected(); //记录连接的信息
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("断开连接");
        channel.attr(WORKER_KEY).setIfAbsent(null);
        group.remove(channel);
        log.info("通道关闭");
        worker.onDisconnected();
        worker = null;
        channel = null;
        super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }


}
